# ==============================================================================
#
# imsldap.pm
#
# GSBIMS LDAP utility routines
#
# $Id: imsldap.pm,v 1.7 2006/07/26 17:18:58 dyoung2 Exp $
#
# Darren Young [darren.young@gsb.uchicago.edu]
#
# ==============================================================================
#
# ChangeLog
#
# $Log: imsldap.pm,v $
# Revision 1.7  2006/07/26 17:18:58  dyoung2
#   * MARKED AS DEPRECATED
#
# Revision 1.6  2005/09/01 15:32:00  dyoung2
#   * Changed over to use _ldapConnect().
#
# Revision 1.5  2005/08/26 22:23:31  dyoung2
#   * Renamed _validIMSMailAccount to _isValidIMSMailAccount
#
# Revision 1.4  2005/08/25 22:38:26  dyoung2
#   * Standardized BEGIN headers.
#
# Revision 1.3  2005/08/25 18:17:34  dyoung2
#   * Corrected library locations
#
# Revision 1.2  2005/06/27 16:31:26  dyoung2
#   * Added _isValidIMSAccount()
#
# Revision 1.1  2005/06/16 17:46:50  dyoung2
#   * Initial version
#
# ==============================================================================

### NOTE: THIS MODULE HAS BEEN DEPRECATED: USE LDAP.PM INSTEAD ###

my  $cvsid   = '$Id: imsldap.pm,v 1.7 2006/07/26 17:18:58 dyoung2 Exp $';
my  @cvsinfo = split( ' ', $cvsid );
our $NAME    = File::Basename::basename($0);
our $VERSION = $cvsinfo[2];


# ------------------------------------------------------------------------------
#                             B E G I N
# ------------------------------------------------------------------------------
BEGIN {

    # Pragmas
    use strict;

    # "Standard" modules we use
    use FindBin;
    use Config::Simple;
    use lib "$FindBin::Bin/../lib";

    # Standard account maint modules to use
    use logging;
    use errcodes;
    use utils;
    
    # Modules that this module uses
    use amtools;
    use ldap;
    use Net::LDAP;
    use Lingua::EN::NameParse;

}


# ------------------------------------------------------------------------------ 
#                             V A R I A B L E S
# ------------------------------------------------------------------------------ 
our $LOGFILE    = "$FindBin::Bin/../log/acctmgr.log" unless($LOGFILE); 
our $CONFIGFILE = "$FindBin::Bin/../etc/acctmgr.cfg" unless($CONFIGFILE); 


# ------------------------------------------------------------------------------
#                             C O N F I G   F I L E
# ------------------------------------------------------------------------------
our $CFG = new Config::Simple( filename => $CONFIGFILE ) or die "$!\n" unless($CFG);


# =============================================================================
# NAME        : _validIMSLdapAccount
# DESCRIPTION : checks LDAP on GSBIMS to see if it exists or not
# REQUIRES    : string(login)
# RETURNS     : TRUE or FALSE
# NOTES       :
# =============================================================================
sub _isValidIMSLdapAccount {
    my ($uname) = @_;
    my $name = "_isValidIMSLdapAccount";
    my ( $package, $filename, $line ) = caller;
    debug("$name: entering with args @_");
    debug("$name: called from package->$package, filename->$filename, line->$line");

    my $retval     = 0;
    my $ldap       = _ldapConnect("ims");
    my $basedn     = $CFG->param("ldapims.basedn");


    debug("$name: searching for $uname in $basedn");
    my $mesg = $ldap->search( base   => "$basedn",
                              filter => '(&(uid=' . $uname . '))' );
    if ( $mesg->code ) {
        logmsg("$name: LDAP search failed on $conn");
        logmsg("$name: LDAP error code is: " . $mesg->code );
        logmsg("$name: LDAP error text is: " . $mesg->error );
        $retval = 0;
    } else {
        if ( $mesg->count == 0 ) {
            debug("$name: no entry for $uname in $basedn");
            $retval = 0;
        } elsif ( $mesg->count == 1 ) {
            debug("$name: found 1 entry for $uname in $basedn");
            $retval = 1;
        } elsif ( $mesg->count > 1 ) {
            logmsg( "$name: *** WARNING *** found more than 1 entry for $uname in $basedn" );
            $retval = 1;
        }
    }
    
    _ldapClose($ldap);

    debug("$name: returning with val $retval");
    return ($retval);
}


# =============================================================================
# NAME        : _createIMSLdapAccount
# DESCRIPTION :
# REQUIRES    :
# RETURNS     :
# NOTES       :
# =============================================================================
sub _createIMSLdapAccount {
    my ( $uname, $firstname, $lastname, $acc_type, $pass_type, $password ) = @_;
    my $name = "_createIMSLdapAccount";
    my ( $package, $filename, $line ) = caller;
    debug("$name: entering with args @_");
    debug("$name: called from package->$package, filename->$filename, line->$line");
    
    my $dn;
    my $fullname;
    my $userpass;
    
    my $mail;
    my $mailAlt1;
    my $mailAlt2;
    my $mailAlt3;
    
    my $defdomain = $CFG->param('mail.defdomain');
    my $altdomain = $CFG->param('mail.altdomain');    
    my $mailhost  = $CFG->param('mail.mailhost');

    # LDAP settings
    my $retval     = 0;
    my $ldap       = _ldapConnect("ims");
    my $basedn     = $CFG->param("ldapims.basedn");
    
    
    ###
    ### Create / generate the value for the userPassword attribute
    ### Currently, the only supported encryption method is UNIX 'crypt'
    ###
    
    # If we were given a crypted password, simply prepend {crypt} to it
    if ( $pass_type eq "crypt" ) {        

        $userpass = '{crypt}' . $password;

    # otherwise, if we were given a plain password, generate a random salt
    # then crypt it and prepend THAT with {crypt}.
    } elsif ( $pass_type eq "plain" ) {    

        my $salt = join '', ('.', '/', 0..9, 'A'..'Z', 'a'..'z')[rand 64, rand 64];
        $userpass = '{crypt}' . crypted($password, $salt);

    # and in the end if we're here then they gave us an invalid password type
    } else {
        logmsg("$name: FAILED because invalid pass_type ($pass_type) was passed");
        return(PERL_FALSE);    
    }


    ###
    ### Build / create their email addresses based on the account type
    ### Staff and Faculty get first.last@ as well as login@
    ### Everyone else only gets login@
    ###

    # Build based on staff and faculty account classes
    if ( $acc_type eq 's' || $acc_type eq 'f' ) {
        $mail     = "$fnam" . '.' . "$lnam" . '@' . $defdomain;
        $mailAlt1 = "$fnam" . '.' . "$lnam" . '@' . $altdomain;
        $mailAlt2 = "$uname" . '@' . $defdomain;
        $mailAlt3 = "$uname" . '@' . $altdomain;
    } else {
        $mail     = "$uname" . '@' . $defdomain;
        $mailAlt1 = "$uname" . '@' . $altdomain;    
    }


    # attempt to connect to the LDAP service. if we connect, move on, otherwise
    # we have to return a fatal error condidtion
    if ( $ldap  = Net::LDAP->new($conn, => timeout=>$timeout, version=>$ldapver)) {
        debug("$name: established LDAP connection to $conn");
    } else {
        logmsg("$name: FAILED to estblish LDAP connection to $conn");
        return(0);
    }

    if ( $ldap->bind( $binduser, password => $bindpass ) ) {
        debug("$name: successful bind to $conn");
    } else {
        logmsg("$name: FAILED to bind to LDAP server $conn");
        logmsg("$name: LDAP error code is " . $ldap->code);
        logmsg("$name: LDAP error text is " . $ldap->error);
        return(0);
    }

    $dn = "uid=$uname" . ',ou=people,o=gsb,dc=uchicago,dc=edu';
    logmsg("$name: setting DN: $dn");

    my $retval = 1;
    my $result = $ldap->add( "$dn",
                             attr => ['cn'                   => qq($first_name) . " " . qq($last_name),
                                      'givenname'            => qq($first_name),
                                      'gsbaccountstatus'     => 'A',
                                      'gsbaccounttype'       => "$acc_type",
                                      'sn'                   => qq($last_name),
                                      'mail'                 => "$mail",
                                      'uid'                  => "$uname",
                                      'userPassword'         => '{crypt}' . "$userPassword",
                                      'mailUserStatus'       => 'active',
                                      'inetUserStatus'       => 'active',
                                      'mailHost'             => 'gsbims.uchicago.edu',
                                      'mailMessageStore'     => 'primary',
                                      'mailDeliveryOption'   => 'mailbox',
                                      'mailAlternateAddress' => $mailAlt1,
                                      'objectclass'          => [
                                          'top',
                                          'person',
                                          'organizationalPerson',
                                          'inetOrgPerson',
                                          'gsbperson',
                                          'inetMailUser',
                                          'ipuser',
                                          'inetuser',
                                          'inetlocalmailrecipient',
                                          'nsManagedPerson'
                                      ],
                             ]
                             );

    if ( $result->code ) {
        logmsg("$name: FAILED to add LDAP account for user $uname");
        logmsg( "$name: LDAP error is: " . $result->error );
        $retval = 0;
    } else {
        logmsg("$name: added LDAP account to $host:$port for user $uname");
    }

    if ($ldap) {
        $ldap->unbind;
    }

    logmsg("$name: returning with val $retval");
    return $retval;

}


# =============================================================================
# NAME        :
# DESCRIPTION :
# REQUIRES    :
# RETURNS     :
# NOTES       :
# =============================================================================
sub _emailacctchk {    ## replaces sub alias_search  added by Brad##

    ### checks to see if email alias account exists ##
    my ( $email, $type, $o ) = @_; ## emailAdd, mail or mailAlternateAddress, 2 o's people & alias##
    my $name = "_emailacctchk";
    logmsg("$name: entering with args @_");

    my $host       = $CFG->param("ldapims.host");
    my $port       = $CFG->param("ldapims.port");
    my $dmb        = $CFG->param("ldapims.binduser");
    my $dmbPass    = $CFG->param("ldapims.bindpw");
    my $connstring = $host . ':' . "$port";

    fixme("fix ldap here");
    my $ldap = Net::LDAP->new($connstring)
      or warn("sub _emailacctchk :can't bind to LDAPIMS server");

    $ldap->bind( $dmb, password => "$dmbPass" );

    my $dnb       = 'ou=' . "$o" . ',o=gsb,dc=uchicago,dc=edu';
    my $filterval = '(|(' . "$type" . '=' . "$email" . '@*))';
    logmsg("$name: search base->$dnb");
    logmsg("$name: filter->$filterval");

    my $mesg = $ldap->search( base   => "$dnb",
                              filter => "$filterval" );

    my $retval = 0;

    if ( $mesg->count > 0 ) {
        my $retval = 1;    ## found ##
    }

    logmsg("$name: returning with val $retval");
    return $retval;
}


# =============================================================================
# NAME        :
# DESCRIPTION :
# REQUIRES    :
# RETURNS     :
# NOTES       :
# =============================================================================
sub _isValidIMSMailAccount {
    my ($chkuname) = @_;
    my $name = "_validIMSMailAccount";
    logmsg("$name: entering with args @_");

    my $retval = 0;

    debug("$name: calling sub _emailacctchk()");
    if ( _emailacctchk( $chkuname, 'mail', 'people' ) ) {
        logmsg("$name: email account $chkuname already in use for ou=people");
        $retval = 1;
    }

    debug("$name: calling sub _emailacctchk()");
    if ( _emailacctchk( $chkuname, 'mail', 'aliases' ) ) {
        logmsg("$name: email account $chkuname already in use for ou=aliases");
        $retval = 1;
    }

    logmsg("$name: returning with val $retval");
    return ($retval);
}

1;
